package com.ruoyi.api.controller;


import com.ruoyi.api.SearchRepository;
import com.ruoyi.api.common.AppController;
import com.ruoyi.api.domin.Employee;
import com.ruoyi.framework.interceptor.annotation.IgnoreAuth;

import java.util.List;

import org.elasticsearch.common.Strings;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;

import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;

import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.core.query.SearchQuery;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.*;

/**
 * @author ywh
 * @date 2021/2/2
 * @desc
 */
@RestController
@RequestMapping("/api/es")
public class EsController extends AppController {

    @Autowired
    private SearchRepository esRepository;

    @Autowired
    private ElasticsearchTemplate elasticsearchTemplate;

    /*增加*/
    @RequestMapping("/save")
    @IgnoreAuth
    public void save() {
        Employee em = new Employee();
        em.setWorkId(11L);
        em.setName("我爱学习真不错");
        em.setAge(21);
        em.setSex("女");
        em.setCreateTime(new Date());
        esRepository.save(em);
    }


    @RequestMapping("/findById")
    @IgnoreAuth
    public Object findById(Long workId) {

        return writeResultRep(esRepository.findById(workId));
    }

    @RequestMapping("/deleteAll")
    @IgnoreAuth
    public void deleteAll() {

        esRepository.deleteAll();
    }


    /*指定字段 ===>条件查询*/
    @RequestMapping("/selectListByItem")
    @IgnoreAuth
    public Object selectListByItem( Long workId, String name) {
        //检索条件
        BoolQueryBuilder condition = QueryBuilders.boolQuery();
        if (workId != null)
            condition.must(QueryBuilders.matchPhraseQuery("workId", workId));
        if (!Strings.isEmpty(name))
            condition.must(QueryBuilders.queryStringQuery(name).field("name"));
        //排序条件
        FieldSortBuilder sort = SortBuilders.fieldSort("createTime").order(SortOrder.DESC);
        //分页条件
        Pageable pageable = PageRequest.of( 1, 10);
        //构建查询
        SearchQuery query = new NativeSearchQueryBuilder()
                .withQuery(condition)
                .withSort(sort)
                .withPageable(pageable)
                .build();
        Page<Employee> searchResponse = esRepository.search(query);

        return searchResponse.getContent();

    }


    /**
     * 多条件查询
     *
     *
     QueryBuilder 是es中提供的一个查询接口, 可以对其进行参数设置来进行数据查询

     1.termQuery("key",obj)完全匹配

     QueryBuilders.termQuery("name","v1");
     2.termsQuery("key",obj1,obj2...)一次匹配多值

     QueryBuilders.termsQuery("name","v1","v2","v3");
     3.matchQuery("key",obj)单个匹配，field不支持通配符，前缀具有高级特性

     4.multiMatchQuery("text","field1","field2",...)匹配多个字段，field有通配符

     5.matchAllQuery();匹配所有文件

     mathcQuery与termQuery区别：

     matchQuery：会将搜索词分词，再与目标查询字段进行匹配，若分词中的任意一个词与目标字段匹配上，则可查询到。

     termQuery：不会对搜索词进行分词处理，而是作为一个整体与目标字段进行匹配，若完全匹配，则可查询到。


     组合查询
     6.must(QueryBuilders): AND

     7.mustNot(QueryBUilders):NOT

     8.should :OR
     QueryBuilders
     .boolQuery()
     .must(QueryBuilders.termQuery("name","Hello"))
     .mustNot(QueryBuilders.termQuery("isEnable",true))
     .should(QueryBuilders.termQuery("age","233"));

     9.只根据id查询
     QueryBuilders.idsQuery(String ..type).ids(Collection<String>ids)；
     QueryBuilders.idsQuery().ids("CHszwWRURyK08j01p0Mmug", "ojGrYKMEQCCPvh75lHJm3A");

     10.范围查询
     QueryBuilder queryBuilder = QueryBuilders.rangeQuery("user")
     .from("kim")
     .to("lucy")
     .includeLower(true) //包含上界
     .includeUpper(true); //包含下届
     11.通配符查询（支持* 匹配任何字符序列，包括空 避免*开始，会检索大量内容造成效率缓慢）
     QueryBuilder queryBuilder = QueryBuilders.wildcardQuery("user","he*o");
     12.分词 模糊查询 fuzzy query
     QueryBuilders.fuzzyQuery("name","hello");
     13.前缀匹配查询 prefix query
     QueryBuilders.prefixQuery("name","hello");
     */
    @RequestMapping("/selectListByStr")
    @IgnoreAuth
    public Object selectListByStr(String inputStr) {
        //1.创建QueryBuilder(即设置查询条件)这儿创建的是组合查询(也叫多条件查询),后面会介绍更多的查询方法
        /*组合查询BoolQueryBuilder
    * must(QueryBuilders)   :AND
    * mustNot(QueryBuilders):NOT
    * should:         :OR
  */
        BoolQueryBuilder builder = QueryBuilders.boolQuery();
        //builder下有must、should以及mustNot 相当于sql中的and、or以及not


        //设置模糊搜索,博客的简诉中有学习两个字
        builder.should(QueryBuilders.fuzzyQuery("name", inputStr));

        //设置要查询博客的标题中含有关键字
        //builder.must(new QueryStringQueryBuilder(inputStr).field("sex"));
        builder.should(QueryBuilders.fuzzyQuery("sex", inputStr));

        //按照博客的评论数的排序是依次降低
        FieldSortBuilder sort = SortBuilders.fieldSort("createTime").order(SortOrder.DESC);

        //设置分页(从第一页开始，一页显示10条)
        //注意开始是从0开始，有点类似sql中的方法limit 的查询
        PageRequest pageRequest = new PageRequest(0, 10);

        //2.构建查询
        NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder();
        //将搜索条件设置到构建中
        nativeSearchQueryBuilder.withQuery(builder);
        //将分页设置到构建中
        nativeSearchQueryBuilder.withPageable(pageRequest);
        //将排序设置到构建中
        nativeSearchQueryBuilder.withSort(sort);
        //生产NativeSearchQuery
        NativeSearchQuery query = nativeSearchQueryBuilder.build();

        //3.执行方法1
        Page<Employee> page = esRepository.search(query);

        //执行方法2：注意，这儿执行的时候还有个方法那就是使用elasticsearchTemplate
        //执行方法2的时候需要加上注解
        //@Autowired
        //private ElasticsearchTemplate elasticsearchTemplate;
        List<Employee> empList = elasticsearchTemplate.queryForList(query, Employee.class);

        //4.获取总条数(用于前端分页)
        int totalNum = (int) page.getTotalElements();
        int totalPages = page.getTotalPages();

        System.out.println("获取总条数为:" + totalNum);
        System.out.println("获取总页数为:" + totalPages);

        //5.获取查询到的数据内容（返回给前端）
        List<Employee> list = page.getContent();

        return writeResultRep(list);
    }

}
